package com.da.core.context;

import com.da.core.util.Utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author da
 * @time 2023/9/16 上午 10:09
 */
public class Request {
    private static final String BOUNDARY_PREFIX = "boundary=";
    private final Context context;
    /**
     * 上传的文件对象
     */
    private MultipartFile multipartFile;

    public MultipartFile getMultipartFile() {
        return this.multipartFile;
    }

    public Request(Context context) {
        this.context = context;
    }

    //    解析请求
    public void resolveRequest(BufferedReader reader) throws IOException {
        // 读取请求行
        requestOneLine(reader);
//        处理请求头
        String line;
        while (null != (line = reader.readLine()) && !line.isEmpty()) {
            final String[] kvl = line.split(": ");
            if (2 == kvl.length) {
                context.getParams().put(kvl[0].replaceAll("\"", ""), kvl[1].replaceAll("\"", ""));
            }
        }
//        处理session,保存 session 在 App 上
        String sessionId = context.getSessionId();
//        获取或者创建 Session
        context.getOrCreateSession(sessionId);
//        解析POST请求
        resolvePOST(reader);
    }

    private void resolvePOST(BufferedReader reader) throws IOException {
        if ("POST".equals(context.getMethod())) {
            final String cl = context.getParams().get("Content-Length");
            if (null != cl && !cl.isEmpty()) {
//                获取消息长度
                int contentLength = Integer.parseInt(cl);
//                获取消息类型
                final String ct = context.getParams().get("Content-Type");
                if (null != ct && !ct.isEmpty()) {
//                    处理 application/json
                    if (ct.contains("application/json")) {
                        char[] requestBody = new char[(int) contentLength];
                        int read = reader.read(requestBody);
                        if (read < 0) {
                            throw new IOException("解析POST请求信息异常");
                        }
                        // 对获取的数据进行处理，例如将正文数据转换为字符串
                        String response = new String(requestBody);
                        Map<String, String> json = parseSimpleJson(response);
                        if (!json.isEmpty()) {
                            context.getParams().putAll(json);
                        }
                    } else if (ct.contains("application/x-www-form-urlencoded")) { // 处理 application/x-www-form-urlencoded
                        System.out.println("处理application/x-www-form-urlencoded");
                    } else if (ct.contains("multipart/form-data")) {
                        // 处理 multipart/form-data 类型的数据
                        processMultipartFormData(reader, contentLength, ct);
                    } else {
                        throw new IOException("不支持的类型");
                    }
                }
            }
        }
    }

    //    解析请求第一行
    private void requestOneLine(BufferedReader reader) throws IOException {
        String url;
        String requestLine = reader.readLine();
        if (requestLine != null && !requestLine.isEmpty()) {
            String[] mpx = requestLine.split(" ");
            if (mpx.length == 3) {
                context.setMethod(mpx[0]);
//                    解析query参数 /a?name=da&age=23
                URL queryUrl = new URL("http://localhost" + mpx[1]);
                String query = queryUrl.getQuery();
                if (query != null) {
                    String[] pairs = query.split("&");
                    for (String pair : pairs) {
                        String[] keyValue = pair.split("=");
                        if (keyValue.length == 2) {
                            String key = URLDecoder.decode(keyValue[0], "UTF-8");
                            String value = URLDecoder.decode(keyValue[1], "UTF-8");
                            context.getParams().put(key, value);
                        }
                    }
                    url = mpx[1].split("\\?")[0];
                } else {
                    url = mpx[1];
                }
//                url的中文传过来需要解码
                context.setUrl(URLDecoder.decode(url, "UTF-8"));
                context.setVersion(mpx[2]);
            }
        }

    }

    //    解析简单的json字符串到Map {"name":"测试","age":10}
    private Map<String, String> parseSimpleJson(String json) {
        Map<String, String> map = new HashMap<>();
        json = json.trim();
        json = json.substring(1, json.length() - 1).replaceAll("\"", "");
        final String[] kvs = json.split(",");
        for (String kv : kvs) {
            final String[] kvi = kv.split(":");
            if (2 == kvi.length) {
                map.put(kvi[0], kvi[1]);
            }
        }
        return map;
    }

    //    解析 multipart/form-data 内容
    private void processMultipartFormData(BufferedReader reader, int contentLength, String contentType) throws IOException {
        // 获取边界字符串
        String boundary = getBoundary(contentType);
        if (boundary == null) {
            throw new IOException("无法获取边界字符串");
        }
        // 读取请求体内容
        // 读成char流
        char[] chars = new char[contentLength];
        int read = reader.read(chars);
        if (read < 0) {
            throw new IOException("解析 POST 请求信息异常");
        }
        // 将 char 数组转换为字节数组
        byte[] requestCharData = new String(chars).getBytes();
        // 解析请求体中的各个部分
        multipartFile = parseMultipartFormData(requestCharData, boundary);
    }

    private String getBoundary(String contentType) {
        int boundaryIndex = contentType.indexOf(BOUNDARY_PREFIX);
        if (boundaryIndex >= 0) {
            return contentType.substring(boundaryIndex + BOUNDARY_PREFIX.length());
        }
        return null;
    }

    private MultipartFile parseMultipartFormData(byte[] requestCharData, String boundary) {
        final MultipartFile multipartFile = new MultipartFile();
//        转成字符串
        String requestBodyString = new String(requestCharData, StandardCharsets.UTF_8);
//        获取内容
        String headerAndContent = getPartHeaderAndContent(requestBodyString, boundary);
        String[] hc = headerAndContent.split("\r\n\r\n");
        InputStream is;
        if (hc.length != 2) return null;
//            处理属性
        for (String head : hc[0].split("\r\n")) {
            String[] kvs = head.split(": ");
            if (kvs.length == 2) {
                multipartFile.setHeader(kvs[0], kvs[1]);
            }
        }
//      处理内容
        byte[] contentBytes = hc[1].getBytes(StandardCharsets.UTF_8);
        is = new ByteArrayInputStream(contentBytes);
//         解析字段名和文件名
        String fieldName = null;
        String fileName = null;
        if (multipartFile.getHeaders().containsKey("Content-Disposition")) {
            String[] dispositionParts = multipartFile.getHeaders().get("Content-Disposition").split("; ");
            for (String s : dispositionParts) {
                if (s.startsWith("name=")) {
                    // name="*" => *
                    fieldName = Utils.splitStartAndEnd(s, "\"", "\"");
                } else if (s.startsWith("filename=")) {
                    // filename="*.*" => *.*
                    fileName = Utils.splitStartAndEnd(s, "\"", "\"");
                }
            }
        }
        multipartFile.setFieldName(fieldName);
        multipartFile.setFileName(fileName);
        multipartFile.setInputStream(is);
        return multipartFile;
    }

    /**
     * 获取上传文件的请求头和内容
     *
     * @param part     请求内容
     * @param boundary boundary
     * @return 去除文件开始位置和结束位置
     */
    private String getPartHeaderAndContent(String part, String boundary) {
        // 边界，用于定位内容的起始和结束位置
        String boundaryStart = "--" + boundary + "\r\n";
        String boundaryEnd = "--" + boundary + "--";
        // 获取内容的起始和结束位置
        int contentStartIndex = part.indexOf(boundaryStart) + boundaryStart.length();
        int contentEndIndex = part.indexOf(boundaryEnd, contentStartIndex);
        return part.substring(contentStartIndex, contentEndIndex);
    }

}
